/*
*
* ████████╗░█████╗░███████╗██████╗░░█████╗░
* ╚══██╔══╝██╔══██╗██╔════╝██╔══██╗██╔══██╗
* ░░░██║░░░██║░░██║█████╗░░██████╦╝███████║
* ░░░██║░░░██║░░██║██╔══╝░░██╔══██╗██╔══██║
* ░░░██║░░░╚█████╔╝██║░░░░░██████╦╝██║░░██║
* ░░░╚═╝░░░░╚════╝░╚═╝░░░░░╚═════╝░╚═╝░░╚═╝
* 
*  :: 九方通逊-Henry ::   Copyright©2020 tofba.com  
* 
*/
package com.lmexpress.service.impl;

import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.codehaus.jackson.JsonNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.lmexpress.enums.ApiCredential;
import com.lmexpress.enums.ApiOrderError;
import com.lmexpress.enums.LabelSuffix;
import com.lmexpress.orm.dhlglobalmail.ConsigneeAddress;
import com.lmexpress.orm.dhlglobalmail.CustomsDetail;
import com.lmexpress.orm.dhlglobalmail.DhlShipment;
import com.lmexpress.orm.dhlglobalmail.Package;
import com.lmexpress.orm.dhlglobalmail.PackageDetails;
import com.lmexpress.orm.dhlglobalmail.ReturnAddress;
import com.lmexpress.orm.openapi.ExpressOrderApi;
import com.lmexpress.orm.openapi.OrderInvoice;
import com.lmexpress.orm.rest.ApiLabelResponse;
import com.lmexpress.orm.rest.ApiOrderResponse;
import com.lmexpress.service.ApiService;
import com.lmexpress.util.ApiUtil;
import com.lmexpress.util.HttpClientPoolUtil;
import com.lmexpress.util.HttpClientResult;
import com.lmexpress.util.JsonConverter;
import com.lmexpress.util.PropertiesUtil;

/**
 * <DHL EC> </br>
 * <说明:2021年1月废弃使用>
 * 2.1 Authentication https://api.dhlglobalmail.com/docs/v2/auth.html </br>
 * 2.2 Label https://api.dhlglobalmail.com/docs/v2/label.html </br>
 * 2.3 Closeout https://api.dhlglobalmail.com/docs/v2/closeout.html</br>
 * 2.4 Track https://api.dhlglobalmail.com/docs/v2/track.html</br>
 * 
 * @author Henry(fba02)
 * @version [版本号, 2020-12-09]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
public class DhlGlobalMailClient implements ApiService {
	private Logger LOGGER = LoggerFactory.getLogger(DhlGlobalMailClient.class);
	private final static String COUNTRY = "US";
	private final static String ORDER_FLAG = "JFTX";
	private final static Integer SUCCESS_CODE = 200;
	private final static String LABEL = "https://api.dhlecs.com/shipping/v4/label?format=PNG";
	private final static String ACCESS_TOKEN = "https://api.dhlglobalmail.com/v2/label/multi/image.json";

	@Override
	public ApiOrderResponse preProcessCreateOrder(ExpressOrderApi expressOrderApi) {
		String countryCode = expressOrderApi.getCountryCode();
		String consigneeState = expressOrderApi.getConsigneeState();
		if (StringUtils.isBlank(countryCode) || StringUtils.isNotBlank(countryCode) && !StringUtils.equalsIgnoreCase(countryCode, COUNTRY)) {
			return new ApiOrderResponse(false, null, PropertiesUtil.getProperty("dhl.globalmail.only.support.us"), false, null);
		}
		expressOrderApi.setCountryCode(expressOrderApi.getCountryCode().toUpperCase());
		if (StringUtils.isBlank(consigneeState)) {
			return new ApiOrderResponse(false, null, PropertiesUtil.getProperty("dhl.globalmail.consignee.state.required"), false, null);
		}
		String consigneeCompanyName = StringUtils.isBlank(expressOrderApi.getConsigneeCompanyName()) ? expressOrderApi.getConsigneeName() : expressOrderApi.getConsigneeCompanyName();
		expressOrderApi.setConsigneeCompanyName(consigneeCompanyName);
		if (StringUtils.isNotBlank(consigneeState)) {
			consigneeState = consigneeState.toUpperCase();
		}
		Map<String, String> allAmericaState = ApiUtil.getAllAmericaState();
		Map<String, String> allAmericaState2 = ApiUtil.getAllAmericaState2();
		if (consigneeState.length() <= 2) {
			// 如果大写的能获取到 就是二字代码是正确的
			String upperCaseState = allAmericaState.get(consigneeState.toString());
			if (StringUtils.isEmpty(upperCaseState)) {
				return new ApiOrderResponse(false, null, PropertiesUtil.getProperty("dhl.globalmail.consignee.state.error"), false, null);
			} else {
				expressOrderApi.setConsigneeState(consigneeState);
			}
		} else {
			// 如果不是二字代码
			String upperCaseState = allAmericaState2.get(consigneeState.toString());
			if (StringUtils.isEmpty(upperCaseState)) {
				return new ApiOrderResponse(false, null, PropertiesUtil.getProperty("dhl.globalmail.consignee.state.error"), false, null);
			} else {
				expressOrderApi.setConsigneeState(upperCaseState);
			}
		}
		if (StringUtils.isBlank(consigneeState)) {
			return new ApiOrderResponse(false, null, PropertiesUtil.getProperty("dhl.globalmail.consignee.state.required"), false, null);
		}
		String customerInvoiceCode = expressOrderApi.getCustomerInvoiceCode();
		customerInvoiceCode = customerInvoiceCode.replaceAll("-", "").replaceAll("_", "");
		expressOrderApi.setCustomerInvoiceCode(customerInvoiceCode);
		// 4位固定
		if (customerInvoiceCode.length() > 26) {
			return new ApiOrderResponse(false, null, PropertiesUtil.getProperty("dhl.globalmail.customer.invoice.code.gt.30.char"), false, null);
		}
		expressOrderApi.setCustomerInvoiceCode(ORDER_FLAG + expressOrderApi.getCustomerInvoiceCode());
		return null;
	}

	@Override
	public String mapping(ExpressOrderApi expressOrderApi) {
		DhlShipment shipment = new DhlShipment();
		Map<String, String> apiCredentials = expressOrderApi.getApiCredentials();
		// 账号默认LAX 5360661-(USLAX1) / 5360660-(USEWR1)
		shipment.setPickup(apiCredentials.get(ApiCredential.DHLEC_PICKUP_LAX.getKey()));//
		shipment.setDistributionCenter(apiCredentials.get(ApiCredential.DHLEC_DISTRIBUTION_CENTER_LAX.getKey()));// 配送中心
		// 构建DHL包裹信息
		List<Package> packages = new ArrayList<Package>();
		Package dhlPackage = new Package();
		packages.add(dhlPackage);
		// 收货人
		ConsigneeAddress consigneeAddress = new ConsigneeAddress();
		consigneeAddress.setAddress1(expressOrderApi.getConsigneeAddress());
		consigneeAddress.setCity(expressOrderApi.getConsigneeCity());
		consigneeAddress.setState(expressOrderApi.getConsigneeState());
		consigneeAddress.setCompanyName(expressOrderApi.getConsigneeCompanyName());
		consigneeAddress.setCountry(expressOrderApi.getCountryCode());
		consigneeAddress.setEmail(expressOrderApi.getConsigneeEmail());
		consigneeAddress.setIdNumber(null);
		consigneeAddress.setIdType(null);
		consigneeAddress.setName(expressOrderApi.getConsigneeName());
		consigneeAddress.setPhone(StringUtils.isBlank(expressOrderApi.getConsigneeMobile()) ? expressOrderApi.getConsigneeTelephone() : expressOrderApi.getConsigneeMobile());
		consigneeAddress.setPostalCode(expressOrderApi.getConsigneePostCode());
		dhlPackage.setConsigneeAddress(consigneeAddress);
		// 包裹详情
		PackageDetails packageDetails = new PackageDetails();
		packageDetails.setPackageId(expressOrderApi.getCustomerInvoiceCode());
		// packageDetails.setPackageRefName("US-A");
		// packageDetails.setPackageDesc("测试下单");
		// 7
		packageDetails.setMailType(Integer.valueOf(ApiCredential.DHLEC_MAILTYPE.getValue()));
		// 账单识别码
		packageDetails.setBillingRef1(apiCredentials.get(ApiCredential.DHLEC_BILLINGREF1.getKey()));
		// 退件地址
		ReturnAddress returnAddress = new ReturnAddress();
		returnAddress.setAddress1(apiCredentials.get(ApiCredential.DHLEC_RETURNADDRESS.getKey()));
		returnAddress.setCity(apiCredentials.get(ApiCredential.DHLEC_RETURNADDRESS_CITY.getKey()));
		returnAddress.setState(apiCredentials.get(ApiCredential.DHLEC_RETURNADDRESS_STATE.getKey()));
		returnAddress.setCountry(apiCredentials.get(ApiCredential.DHLEC_RETURNADDRESS_COUNTRY.getKey()));
		returnAddress.setPostalCode(apiCredentials.get(ApiCredential.DHLEC_RETURNADDRESS_POSTALCODE.getKey()));
		returnAddress.setCompanyName(apiCredentials.get(ApiCredential.DHLEC_RETURNADDRESS_COMPANYNAME.getKey()));
		dhlPackage.setReturnAddress(returnAddress);
		List<OrderInvoice> orderInvoices = expressOrderApi.getOrderInvoices();
		Double weightDouble = 0D;
		if (CollectionUtils.isNotEmpty(orderInvoices)) {
			// 产品信息
			List<CustomsDetail> customsDetails = new ArrayList<CustomsDetail>();
			CustomsDetail customsDetail = null;
			for (OrderInvoice orderInvoice : orderInvoices) {
				customsDetail = new CustomsDetail();
				customsDetail.setHsCode(orderInvoice.getHsCode());
				customsDetail.setSkuNumber(orderInvoice.getSkuCode());
				customsDetail.setItemDescription(orderInvoice.getSkuNameEn() + "," + orderInvoice.getSkuNameCn());
				customsDetail.setPackagedQuantity(orderInvoice.getInvoicePcs());
				customsDetail.setItemValue(orderInvoice.getInvoiceAmount());
				customsDetails.add(customsDetail);
				weightDouble += (orderInvoice.getInvoiceWeight() == null ? 0D : orderInvoice.getInvoiceWeight());
			}
			dhlPackage.setCustomsDetails(customsDetails);
		}
		shipment.setPackages(packages);
		Double weight = (expressOrderApi.getWeight() == null || (expressOrderApi.getWeight() != null && expressOrderApi.getWeight() == 0D)) ? weightDouble : expressOrderApi.getWeight();
		if (null != weight) {
			packageDetails.setWeight(weight);
		}
		packageDetails.setWeightUom(ApiCredential.DHLEC_WEIGHT_UOM.getValue());
		// 0.0022046
		packageDetails.setOrderedProduct(Integer.valueOf(ApiCredential.DHLEC_GROUND.getValue()));
		if (null != weight) {
			Double weightlb = weight * 2.2046;
			if (weightlb > 1) {
				packageDetails.setOrderedProduct(Integer.valueOf(ApiCredential.DHLEC_PLUS_GROUND.getValue()));
			}
		}
		dhlPackage.setPackageDetails(packageDetails);
		// return dhlShipment;
		List<DhlShipment> shipments = new ArrayList<DhlShipment>();
		shipments.add(shipment);
		Map<String, Object> shipmentsMap = new HashMap<String, Object>();
		shipmentsMap.put("shipments", shipments);
		return new Gson().toJson(shipmentsMap);
	}

	@Override
	public ApiOrderResponse createOrder(ExpressOrderApi expressOrderApi) {
		try {
			// 前置数据校验
			ApiOrderResponse apiOrderResponse = preProcessCreateOrder(expressOrderApi);
			if (null != apiOrderResponse) {
				return apiOrderResponse;
			}
			String orderJson = mapping(expressOrderApi);
			LOGGER.info("dhlglobalmail.shipment.request:{}", orderJson);
			Map<String, String> apiCredentials = expressOrderApi.getApiCredentials();
			String accessToken = apiCredentials.get(ApiCredential.DHLEC_ACCESS_TOKEN.getKey());
			if (StringUtils.isBlank(accessToken)) {
				return new ApiOrderResponse(false, null, PropertiesUtil.getProperty("dhl.globalmail.access.token.blank"));
			}
			HttpClientResult httpClientResult = HttpClientPoolUtil.doPost(LABEL + "?access_token=" + accessToken + "&client_id=" + apiCredentials.get(ApiCredential.DHLEC_CLIENTID.getKey()), HttpClientPoolUtil.setJsonHeader(), orderJson);
			if (null == httpClientResult || (null != httpClientResult && StringUtils.isBlank(httpClientResult.getContent()))) {
				return new ApiOrderResponse(false, null, ApiOrderError.SERVICE_NO_DATA_RETURN.getMessage(), true, null);
			}
			String responseJson = httpClientResult.getContent();
			LOGGER.info("dhlglobalmail.shipment.response.{}", responseJson);
			if (StringUtils.isBlank(responseJson)) {
				return new ApiOrderResponse(false, null, ApiOrderError.SERVICE_NO_DATA_RETURN.getMessage(), true, null);
			}
			return null;
			// return analyzeShippingLabelResponseResult(responseJson, expressOrderApi);
		} catch (Exception e) {
			LOGGER.error("dhlglobalmail.shipment.exception", e);
			return new ApiOrderResponse(false, null, ApiOrderError.CREATE_ORDER_EXCEPTION.getMessage(), false, e.getMessage());
		}
	}

	/**
	 * <获取标签结果分析>
	 * 
	 * @param json
	 * @author Henry(fba02)
	 * @version [版本号, 2019年4月9日]
	 * @see 响应失败:{\
	 *      "meta\":{\"code\":400,\"timestamp\":\"2019-04-07T07:11:33-04:00\"},\"data\":{\"shipments\":[{\"status\":{\"code\":\"ERROR\",\"numRejected\":0,\"numAccepted\":0,\"timestamp\":\"2019-04-07T07:11:33-0400\"},\"errors\":[{\"errorMessage\":\"Pick
	 *      u p is not associated with your
	 *      account\",\"errorCode\":\"VALIDATION_ERROR\",\"errorId\":0}],\"distributionCenter\":\"USORD1\",\"packages\":[],\"pickup\":5300000}]}}
	 */
	public ApiOrderResponse analyzeShippingLabelResponseResult(String json, ExpressOrderApi expressOrderApi) {
		JsonNode metaNode = JsonConverter.getNode(json, "meta");
		JsonNode dataNode = JsonConverter.getNode(json, "data");
		List<JsonNode> metaErrorNodes = metaNode.findValues("error");
		if (CollectionUtils.isNotEmpty(metaErrorNodes)) {
			StringBuffer errorMessageBuffer = new StringBuffer();
			for (JsonNode metaErrorNode : metaErrorNodes) {
				JsonNode errorMessageNode = metaErrorNode.findValue("error_message");
				errorMessageBuffer.append(errorMessageNode.asText()).append(";");
			}
			return new ApiOrderResponse(false, null, errorMessageBuffer.toString(), json);
		}
		Integer code = metaNode.findValue("code").asInt();
		JsonNode shipmentsNode = dataNode.get("shipments");
		// 响应成功
		if (Objects.equals(code, SUCCESS_CODE)) {
			JsonNode labelDetailsNode = shipmentsNode.findValue("labelDetails");
			String trackingNumber = shipmentsNode.findValue("trackingNumber").asText();
			ApiOrderResponse apiOrderResponse = new ApiOrderResponse();
			apiOrderResponse.setSuccess(true);
			String url = labelDetailsNode.findValue("url").asText();
			// String format = labelDetailsNode.findValue("format").asText();
			// String pdfName = trackingNumber + "_original.pdf";
			String pdfName = trackingNumber + LabelSuffix.PNG.getSuffix();
			// 当前月份
			String centrePath = ApiUtil.getCurrentDay() + File.separator;
			String relativePath = DEFAULT_LABEL_FOLDER + File.separator + centrePath;
			String folderPath = DEFAULT_LABEL_ROOT + relativePath;
			if (!new File(folderPath).exists()) {
				new File(folderPath).mkdirs();
			}
			String fileUrl = folderPath + pdfName;
			try {
				// 下载面单到本地
				FileUtils.copyURLToFile(new URL(url), new File(fileUrl));
				apiOrderResponse.setLmLabelUrl(relativePath + pdfName);
			} catch (Exception e) {
				LOGGER.error("dhlglobalmail.copy.url.to.file.exception", e);
			}
			apiOrderResponse.setLabelUrl(url);
			apiOrderResponse.setThirdPartyorderNo(labelDetailsNode.findValue("packageId").asText());
			// 追踪号截取掉前面8位
			if (trackingNumber.length() == 30) {
				trackingNumber = trackingNumber.substring(8, trackingNumber.length());
			}
			apiOrderResponse.setTrackNumber(trackingNumber);
			return apiOrderResponse;
		}
		// 响应失败
		JsonNode errorsNode = shipmentsNode.findValue("errors");
		List<JsonNode> errorMessageNodes = errorsNode.findValues("errorMessage");
		StringBuffer errorMessageBuffer = new StringBuffer();
		for (JsonNode errorMessageNode : errorMessageNodes) {
			String text = errorMessageNode.asText();
			if (StringUtils.isNotBlank(text)) {
				errorMessageBuffer.append(text).append(";");
			}
		}
		ApiOrderResponse apiOrderResponse = new ApiOrderResponse(false, null, errorMessageBuffer.toString(), json);
		List<JsonNode> errorCodeNodes = errorsNode.findValues("errorCode");
		if (CollectionUtils.isNotEmpty(errorCodeNodes)) {
			for (JsonNode errorCodeNode : errorCodeNodes) {
				String errorCode = errorCodeNode.asText();
				// 更新一次令牌INVALID_TOKEN
				if (Objects.equals(errorCode, "INVALID_TOKEN")) {
					apiOrderResponse.setRePush(true);
					break;
				}
			}
		}
		return apiOrderResponse;
	}

	@Override
	public ApiLabelResponse label(String trackNumber, Map<String, String> configureMap) {
		return null;
	}

	@Override
	public ApiLabelResponse label(String referenceNo, String trackNumber, Map<String, String> configureMap) {
		return null;
	}

	@Override
	public ApiLabelResponse labelRender(String trackNumber, ExpressOrderApi expressOrderApi) {
		return null;
	}

	@Override
	public void tracking(String trackNumber, Map<String, String> configureMap) {

	}

	@Override
	public String trackNumber(String code, Map<String, String> configureMap) {
		return null;
	}

	/**
	 * < 获取access_token>
	 * 
	 * @return
	 * @author Henry(fba02)
	 * @version [版本号, 2020-9-27]
	 * @see [类、类#方法、类#成员]
	 */
	public String accessToken(String username, String password) {
		String param = "?username=" + username + "&password=" + password;
		try {
			HttpClientResult httpClientResult = HttpClientPoolUtil.doGet(ACCESS_TOKEN + param, HttpClientPoolUtil.setJsonHeader(), null, true);
			if (null == httpClientResult) {
				return null;
			}
			String responseJson = httpClientResult.getContent();
			if (StringUtils.isBlank(responseJson)) {
				return null;
			}
			LOGGER.info("dhl.access.token:{}", responseJson);
			Map<String, Object> responseMap = new Gson().fromJson(responseJson, new TypeToken<Map<String, Object>>() {
			}.getType());
			if (MapUtils.isEmpty(responseMap)) {
				return null;
			}
			@SuppressWarnings("unchecked")
			Map<String, Object> dataMap = (Map<String, Object>) responseMap.get("data");
			if (MapUtils.isEmpty(dataMap)) {
				return null;
			}
			String accessToken = (String) dataMap.get("access_token");
			if (StringUtils.isNotBlank(accessToken)) {
				return accessToken;
			}
			return null;
		} catch (Exception e) {
			LOGGER.error("dhlglobalmail_access_token_error", e);
			return null;
		}
	}

	/**
	 * @param args
	 * @author Henry(fba02)
	 * @version [版本号, 2020-10-21]
	 * @see [类、类#方法、类#成员]
	 */
//	public static void main(String[] args) {
//		try {
//			Class<?> clazz = Class.forName("com.tofba.service.impl.DhlGlobalMailClient");
//			// username-password-url
//			Method method = clazz.getMethod("accessToken", String.class, String.class, String.class);
//			Object object = method.invoke(clazz.newInstance(), new Object[] { "api.wanbinternational", "F1t3XJjsiNs9x6W7", "https://api.dhlglobalmail.com/v2/auth/access_token" });
//			if (null != object) {
//				System.out.println(object.toString());
//			}
//		} catch (Exception e) {
//			e.printStackTrace();
//		}
//	}
}